#ifndef RACE_H
#define RACE_H

#include <iostream>
#include <vector>
#include <map>

#include "lib.h"
#include "Prerequis.h"
#include "ListCapa.h"
#include "ListEnsCapa.h"
#include "StatusCode.h"

#include <boost/assign/list_of.hpp>

using namespace std;

/**
 * La classe Race représente une race au sens AD&D. C'est une classe
 * abstraite, qui sert au polymorphisme.
 *
 * La classe permet de gérer les diverses capacités raciales et
 * éventuels ensembles raciaux, qui sont lus depuis les types de
 * races. L'objet Race possède les méthodes et attributs communs à
 * toutes les races.
 *
 * @todo Réfléchir à la possibilité d'avoir des conteneurs plutôt que
 * des pointeurs. Cela faciliterait l'implémentation de MetaRace.
 *
 * @author Johan "Solo" Luisier
 */
class Race
{
 protected:
  /**
   * Permet de déterminer si les niveaux de sorties ont bien été
   * initialisés.
   */
  static bool niveauxLus;
  /**
   * Liste des noms des niveaux de sorties paramétrables.
   */
  static const vector< string > NomsNiveaux;
  //static void lireNiveaux();
  /**
   * Structure qui permet de gérer les éventuel bonus pour un trait,
   * qui serait dû à une compétence spécifique. Par exemple un Elfe
   * qui prend la capacité raciale "Dextérité renforcée" (pour 20 pp)
   * a \f$ + 1 \f$ en dextérité. On doit donc stocker dans cette
   * structure le trait potentiellement augmenté, l'éventuel bonus et
   * le numéro de la capacité de laquelle découle le bonus.
   */
  struct bonusConditionnel
  {
    unsigned int TraitNumero; /**< Numéro du trait à modifier */
    unsigned int CapaNumero;  /**< Numéro de la capacité raciale
				 déclenchante. */
    int Ajustement;           /**< Ajustement au trait (\f$ +1 \f$
				 généralement). */
  };

  /**
   * Capacités raciales. On stocke uniquement le numéro de la capacité
   * dans ce conteneur.
   */
  vector<unsigned int> capacites;
  /**
   * Niveau de sortie des méthodes de base, c'est à dire très
   * simple. On peut changer la valeur de cette constante en modifiant
   * la ligne Race::élémentaire du fichier CONFIG.
   */
  static DebugLevelType elementaire;
  /**
   * Niveau de sortie des fonctions plus élaborées. La valeur de cette
   * constante est définie par la ligne Race::fonction du fichier
   * CONFIG.
   */
  static DebugLevelType fonction;
  /**
   * Nom de la Race (Elfe, Gnome, Humain, ...)
   */
  string Type;
  /* /\** */
  /*  * Pointeur sur la liste des capacités raciales, permet d'avoir */
  /*  * accès aux capacités (noms, cout en pp) de la race considérée. */
  /*  *\/ */
  /* const vector< ListCapa > *ptrCapa; */
  /* /\** */
  /*  * Pointeur sur les ensembles raciaux, qui permet d'accéder aux */
  /*  * éventuels ensembles raciaux. Ce pointeur est nul s'il n'existe */
  /*  * pas d'ensembles raciaux. */
  /*  *\/ */
  /* const vector< vector< unsigned int > > *ptrEns; */
  /* /\** */
  /*  * Pointeur sur le nombre de capcités raciales de la Race, relique */
  /*  * du temps où les capacités étaient stockées dans un tableau */
  /*  * statique. */
  /*  *\/ */
  /* const unsigned int *ptrNbrCapa; */
  /* /\** */
  /*  * Pointeur sur le nombre d'ensembles raciaux, datant également du */
  /*  * temps où les ensembles raciaux étaient des tableaux statiques. */
  /*  * Est égal au nombre de lignes de la "matrice" pointée par ptrEns. */
  /*  *\/ */
  /* const unsigned int *ptrNbrEns; */
  /* /\** */
  /*  * Pointeur sur le nombre max de capacités dans un ensemble racial, */
  /*  * donne la longueur maximale des lignes de la matrice pointée pas */
  /*  * ptrEns. */
  /*  *\/ */
  /* const unsigned int *ptrMaxEns; */
  /* /\** */
  /*  * Pointeur sur la liste des ensembles raciaux. Si la Race n'a pas */
  /*  * de tels ensembles, ce pointeur est nul. */
  /*  *\/ */
  /* const vector< ListCapa > *ptrNomEns; */
  /* /\** */
  /*  * Pointeur sur le conteneur des prérequis raciaux. Cela permet */
  /*  * d'éviter de créer un Demi-Ogre avec 20 de Charisme par exemple. */
  /*  *\/ */
  /* const vector< Prerequis > *ptrPreRequis; */
  /**
   * Contient le nombre de capacités raciales disponibles lors de la
   * création.
   */
  unsigned int NombreTotalCapacites;
  /**
   * Nombre d'ensembles raciaux, est égal au nombre de lignes de la
   * matrice EnsemblesRaciaux.
   */
  unsigned int NombreTotalEnsembles;
  /**
   * Nombre maximal de capacités raciales dans un ensemble racial.
   */
  unsigned int NombreMaxCapacites;
  /**
   * Contient les capacités raciales, permet d'avoir accès aux
   * capacités (noms, cout en pp) de la race considérée.
   */
  vector< ListCapa > CapacitesRaciales;
  /**
   * Contient les ensembles raciaux, permet d'avoir accès aux noms et
   * coûts des ensembles, ainsi qu'aux capacités incluses.
   */
  vector< ListEnsCapa > EnsemblesRaciaux;
  /**
   * Contient la liste des prérequis raciaux. Cela permet d'éviter de
   * créer un Demi-Ogre avec 20 de Charisme par exemple.
   */
  vector< Prerequis > PrerequisRaciaux;
  /**
   * Contient les ajustements raciaux sur les traits.
   */
  map< unsigned int, int > AjustementsRaciaux;
  /**
   * Pointeur sur l'éventuel bonus sur un trait. L'existence de ce
   * bonus dépend de la race et de la présence d'une capacité raciale
   * spécifique.
   */
  bonusConditionnel* BonusAuTrait;
 public:
  Race(const string& type);
  Race(const Race& race);
  virtual ~Race();
  void appliquerAjustements(vector< unsigned int >& tab);
  void afficheInfo(ostream& os = blank()) const;
  string getType() const;
  unsigned int getTaille() const;
  unsigned int getCapa(const unsigned int& i) const;
  string getCapacite(const unsigned int& i) const;
  const vector< unsigned int >* getCapacitesAdresse() const;
  void getCapacites(unsigned int& nbr, vector<ListCapa>& capa) const;
  const vector< ListCapa >* getCapacites() const;
  void getDonneesEnsRaciaux(unsigned int& nbr, unsigned int& max) const;
  const vector< ListEnsCapa >* getEnsemblesRaciaux() const;
  //const vector<unsigned int>* getEnsembleRacial(const unsigned int& nbr) const;
  unsigned int getPP() const;
  void setCapacites(const vector<unsigned int>& capa);
  static void setLevel(const unsigned int& level, const unsigned int& n);
  const vector<unsigned int>* getToutesCapacites(unsigned int& nbr) const;
  void construitRace(unsigned int& pps);
  StatusCode rempliPrerequis(vector< unsigned int >& tab);
};


#endif
